﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;

namespace Pariveda.ObjectDataSource.Business
{
    public class ProductController
    {
        /// <summary>
        /// Gets a list of products for display in a grid
        /// </summary>
        /// <param name="categoryId">Category Id to filter by- if null or less than zero, no filter applied</param>
        /// <param name="supplierId">Supplier Id to filter by- if null or less than zero, no filter applied</param>
        /// <param name="sortType">ColumnName to sort by</param>
        /// <param name="startRowIndex">Starting row to return</param>
        /// <param name="maximumRows">Numbers of rows to return</param>
        /// <returns>List of <see cref="ProductGetListResult" /></returns>
        public List<ProductGetListResult> GetList(int? categoryId, int? supplierId, string sortType, int startRowIndex, int maximumRows)
        {
            using (NorthwindDataContext db = new NorthwindDataContext())
            {
                //First we start with the base query
                var productQuery = from p in db.Products
                                   select p;

                //Next we filter if category or supplier has been specified
                productQuery = GetListQuery(productQuery, categoryId, supplierId);

                //Sort the query
                productQuery = GetListSort(productQuery, sortType);

                //Use the Skip and Take methods to limit the results to the page requested
                productQuery = productQuery.Skip(startRowIndex).Take(maximumRows);
                    
                //Project results into a ligher weight class and actually execute the query by
                //calling the ToList method
                return productQuery.Select(p => new ProductGetListResult
                               {
                                   ProductName = p.ProductName,
                                   SupplierName = p.Supplier.CompanyName,
                                   CategoryName = p.Category.CategoryName
                               }).ToList();
            }
        }

        /// <summary>
        /// Returns the total row count for the <seealso cref="GetList"/> query
        /// </summary>
        /// <param name="categoryId">Category Id to filter by- if null or less than zero, no filter applied</param>
        /// <param name="supplierId">Supplier Id to filter by- if null or less than zero, no filter applied</param>
        /// <returns>Total number of rows for the query</returns>
        public int GetListCount(int? categoryId, int? supplierId)
        {
            using (NorthwindDataContext db = new NorthwindDataContext())
            {
                var productQuery = from p in db.Products
                                   select p;

                productQuery = GetListQuery(productQuery, categoryId, supplierId);
                
                return productQuery.Count();
            }
        }

        /// <summary>
        /// Sorts the query by the specified column name
        /// </summary>
        /// <param name="productQuery">Query to be sorted</param>
        /// <param name="sortType">String indication of the column name to sort on</param>
        /// <returns>Sorted queryable <see cref="ProductGetListResult"/></returns>
        private IQueryable<Product> GetListSort(IQueryable<Product> productQuery, string sortType)
        {
            //Determining whether to sort ascending or descending 
            //(GridView appends DESC if the column is clicked on twice to indicate a descending sort)
            bool sortDescending = false;
            if (!String.IsNullOrEmpty(sortType))
            {
                string[] values = sortType.Split(' ');
                sortType = values[0];
                if (values.Length > 1)
                {
                    sortDescending = values[1] == "DESC";
                }
            }

            switch (sortType)
            {
                case "CategoryName":
                    if (sortDescending)
                    {
                        productQuery = productQuery.OrderByDescending(p => p.Category.CategoryName).ThenBy(p => p.ProductName); ;
                    }
                    else
                    {
                        productQuery = productQuery.OrderBy(p => p.Category.CategoryName).ThenBy(p => p.ProductName); ;
                    }
                    break;
                case "SupplierName":
                    if (sortDescending)
                    {
                        productQuery = productQuery.OrderByDescending(p => p.Supplier.CompanyName).ThenBy(p => p.ProductName);
                    }
                    else
                    {
                        productQuery = productQuery.OrderBy(p => p.Supplier.CompanyName).ThenBy(p => p.ProductName);
                    }
                    break;
                default:
                    if (sortDescending)
                    {
                        productQuery = productQuery.OrderByDescending(p => p.ProductName);
                    }
                    else
                    {
                        productQuery = productQuery.OrderBy(p => p.ProductName);
                    }
                    break;
            }

            //The query has not executed during this method, it is only setting up the query for execution
            return productQuery;
        }
        
        /// <summary>
        /// Returns a query to be used by <see cref="GetList"/> and <see cref="GetListCount"/>
        /// </summary>
        /// <param name="db">DataContext the query is based on</param>
        /// <param name="categoryId">Category Id to filter by- if null or less than zero, no filter applied</param>
        /// <param name="supplierId">Supplier Id to filter by- if null or less than zero, no filter applied</param>
        /// <returns>A queryable result set</returns>
        private IQueryable<Product> GetListQuery(IQueryable<Product> productQuery, int? categoryId, int? supplierId)
        {
            //Only filter by category id if specified (query not executed here either)
            if (categoryId.HasValue && categoryId.Value > 0)
            {
                productQuery = productQuery.Where(p => p.CategoryID == categoryId.Value);
            }

            //Only filter by supplier id if specified (query not executed here either)
            if (supplierId.HasValue && supplierId.Value > 0)
            {
                productQuery = productQuery.Where(p => p.SupplierID == supplierId.Value);
            }

            //Return the query (Query isn't even executed when we return it)
            return productQuery;
        }

    }
}
